package com.katesoft.scale4j.agent.jmx;

import com.katesoft.scale4j.agent.ServiceLauncher;
import com.katesoft.scale4j.agent.service.ServiceDetails;
import com.katesoft.scale4j.agent.service.ServiceStatus;
import com.katesoft.scale4j.log.LogFactory;
import com.katesoft.scale4j.log.Logger;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;

import java.util.Date;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentMap;

/**
 * Very simple exporter of agent functionality through JMX.
 * 
 * @author kate2007
 */
@ManagedResource(objectName = IServiceManagerMBean.OBJ_NAME)
public class ServiceManagerJMXExporter implements IServiceManagerMBean {
   private Logger logger = LogFactory.getLogger(getClass());
   private ServiceLauncher launcher;
   private ClassPathXmlApplicationContext context;

   public void setLauncher(ServiceLauncher launcher) {
      this.launcher = launcher;
   }

   // methods
   @Override
   @ManagedOperation
   public boolean isServiceRunning(String name) {
      ServiceDetails details = byName(name);
      return details.getStatus() == ServiceStatus.RUNNING;
   }

   @Override
   @ManagedOperation
   public String serviceStatus(String name) {
      ServiceDetails details = byName(name);
      return details.getStatus().name();
   }

   @Override
   @ManagedOperation
   public String serviceConfiguration(String name) {
      return byName(name).serviceConfiguration();
   }

   @Override
   @ManagedOperation
   public Date startedAt(String name) {
      ServiceDetails details = byName(name);
      return details.launchedAt();
   }

   @Override
   @ManagedOperation
   public String[] allServices() {
      ConcurrentMap<String, ServiceDetails> services = launcher.getServices();
      return services.keySet().toArray(new String[services.size()]);
   }

   @Override
   @ManagedOperation
   public String[] allServicesByStatus() {
      ConcurrentMap<String, ServiceDetails> services = launcher.getServices();
      String[] array = new String[services.size()];
      int i = 0;
      for (Entry<String, ServiceDetails> entry : services.entrySet()) {
         array[i++] = String.format("%s=%s", entry.getKey(), entry.getValue().getStatus().name());
      }
      return array;
   }

   @Override
   @ManagedOperation
   public void stopService(String name, boolean forceKill) throws Exception {
      logger.info("calling jmx.stopService(%s,%s)", name, forceKill);
      byName(name);
      launcher.stopService(name, forceKill);
   }

   @Override
   @ManagedOperation
   public void stop(boolean forceKill) {
      logger.info("calling jmx.stop(%s)", forceKill);
      try {
         launcher.stopAllServices(forceKill);
         context.destroy();
      } catch (Exception e) {
         logger.error(e);
      }
      System.exit(-1);
   }

   @Override
   @ManagedOperation
   public void startService(String name) {
      logger.info("calling jmx.startService(%s)", name);
      byName(name);
      launcher.startService(name);
   }

   private ServiceDetails byName(String name) {
      ServiceDetails details = launcher.getServices().get(name);
      if (details == null) {
         throw new IllegalArgumentException(String.format("service %s not found", name));
      }
      return details;
   }

   public void setContext(ClassPathXmlApplicationContext context) {
      this.context = context;
   }
}
